//dbsvr用hash换出器
#ifndef __DBSVR_HASH_SWAP__
#define __DBSVR_HASH_SWAP__

#include "CTHashObjectMgr.h"
using namespace CTLib;

//hash换出控制器
template<typename KEY,
typename VALUE,
typename HASH_FUNC = __gnu_cxx::hash<KEY>,
typename EQUAL_KEY = std::equal_to<KEY> >
class CTAutoHashSwapMgrForDBsvr : public CTAutoHashSwapMgr<KEY, VALUE, HASH_FUNC, EQUAL_KEY>
{
public:
    typedef CTHashPtr<KEY, VALUE, HASH_FUNC, EQUAL_KEY> HASH_PTR;
    typedef CTAutoHashObjectMgr<KEY, VALUE, HASH_FUNC, EQUAL_KEY> HASH_TYPE;
    typedef int (*UPDATE_FUNC)(HASH_PTR& stPtr);

    //换出检查
    virtual int CheckSwap()
    {
        if (!this->m_pstHash)
        {
            return -1;
        }

        if (!IsNeedSwap())
        {
            return 0;
        }

        CT_TRACE(("begin swap out"));
        HASH_PTR stNowPtr, stNextPtr;
        stNowPtr = this->m_pstHash->GetHeadPtr();
        stNextPtr = this->m_pstHash->GetNextPtr(stNowPtr);
        for (; stNowPtr.IsValid() && IsNeedSwap();)
        {
            if (this->m_pstHash->IsNormal(stNowPtr.GetIndex()))
            {
                SwapOut(stNowPtr);  //在normal链中的元素不需要再更新到数据库
            }

            stNowPtr = stNextPtr;
            stNextPtr = this->m_pstHash->GetNextPtr(stNowPtr);
        }

        return 0;
    }

    //全部换出
    virtual int SwapAllOut()
    {
        if (!this->m_pstHash)
        {
            return -1;
        }
        CT_TRACE(("begin swap all out"));

        HASH_PTR stNowPtr, stNextPtr;
        int iRet = 0;
        stNowPtr = this->m_pstHash->GetHeadPtr();
        stNextPtr = this->m_pstHash->GetNextPtr(stNowPtr);
        for (int i = 0; stNowPtr.IsValid() && i < this->MAX_SWAP_OUT_PER_TIMER;i++)
        {
            if (this->m_pstHash->IsNormal(stNowPtr.GetIndex()))
            {
                SwapOut(stNowPtr);
            }
            else if (this->m_pstHash->IsUpdate(stNowPtr.GetIndex()) || this->m_pstHash->IsSwaping(stNowPtr.GetIndex()))
            {
                iRet = (*this->m_pUpdateFunc)(stNowPtr);
                if (iRet == 0)
                {
                    this->m_pstHash->SetSwaping(stNowPtr);
                }
            }

            stNowPtr = stNextPtr;
            stNextPtr = this->m_pstHash->GetNextPtr(stNowPtr);
        }

        return 0;
    }

    //释放
    virtual int SwapOut(HASH_PTR& stPtr)
    {
        if (!this->m_pstHash)
        {
            return -1;
        }

        if (!stPtr.IsValid())
        {
            return -2;
        }

        CT_TRACE(("swap out cell, index = %d", stPtr.GetIndex()));
        if (!this->m_pstHash->IsNormal(stPtr.GetIndex()))
        {
            CT_ERROR(("swap out not normal cell, index = %d", stPtr.GetIndex()));
            return -3;
        }

        return this->m_pstHash->HashFreeByPtr(stPtr);
    }

    //检查更新
    virtual int CheckUpdate(int iUpdateInterval)
    {
        static int iLastUpdateTime;
        int iNow = time(NULL);
        if (iNow - iLastUpdateTime < iUpdateInterval)
        {
            return 0;
        }
        iLastUpdateTime = iNow;

        int iRet = 0;
        int iUpdateCount = 0;
        HASH_PTR stNowPtr, stNextPtr;
        stNowPtr = this->m_pstHash->GetUpdateHeadPtr();
        stNextPtr = this->m_pstHash->GetUpdateNextPtr(stNowPtr);
        for (; stNowPtr.IsValid() && iUpdateCount < MAX_HASH_UPDATE_COUNT;)
        {
            if (this->m_pstHash->IsUpdate(stNowPtr.GetIndex()) || this->m_pstHash->IsSwaping(stNowPtr.GetIndex()))
            {
                CT_TRACE(("update to db ,index = %d", stNowPtr.GetIndex()));
                iRet = (*this->m_pUpdateFunc)(stNowPtr);
                if (iRet == 0)
                {
                    this->m_pstHash->SetSwaping(stNowPtr);
                    iUpdateCount++;
                }
            }

            stNowPtr = stNextPtr;
            stNextPtr = this->m_pstHash->GetUpdateNextPtr(stNowPtr);
        }

        CT_TRACE(("update %d cell to db", iUpdateCount));
        return 0;
    }

protected:
    virtual bool IsNeedSwap() const
    {
        return ((float)this->m_pstHash->UsedSize() / this->m_pstHash->GetObjectCount() >= this->m_fLimitPercent); 
    }
};

//地图状态更新控制器
template<typename KEY,
typename VALUE,
typename HASH_FUNC = __gnu_cxx::hash<KEY>,
typename EQUAL_KEY = std::equal_to<KEY> >
class CTMapStatSwapMgrForDBsvr : public CTAutoHashSwapMgr<KEY, VALUE, HASH_FUNC, EQUAL_KEY>
{
public:
    typedef CTHashPtr<KEY, VALUE, HASH_FUNC, EQUAL_KEY> HASH_PTR;
    typedef CTAutoHashObjectMgr<KEY, VALUE, HASH_FUNC, EQUAL_KEY> HASH_TYPE;
    typedef int (*UPDATE_FUNC)(HASH_PTR& stPtr);

    //换出检查
    virtual int CheckSwap()
    {
        return 0;
    }

    //全部换出
    virtual int SwapAllOut()
    {
        if (!this->m_pstHash)
        {
            return -1;
        }
        CT_TRACE(("begin swap all out"));

        HASH_PTR stNowPtr, stNextPtr;
        int iRet = 0;
        stNowPtr = this->m_pstHash->GetHeadPtr();
        stNextPtr = this->m_pstHash->GetNextPtr(stNowPtr);
        for (int i = 0; stNowPtr.IsValid() && i < this->MAX_SWAP_OUT_PER_TIMER;i++)
        {
            if (this->m_pstHash->IsNormal(stNowPtr.GetIndex()))
            {
                SwapOut(stNowPtr);
            }
            else if (this->m_pstHash->IsUpdate(stNowPtr.GetIndex()) || this->m_pstHash->IsSwaping(stNowPtr.GetIndex()))
            {
                iRet = (*this->m_pUpdateFunc)(stNowPtr);
                if (iRet == 0)
                {
                    this->m_pstHash->SetSwaping(stNowPtr);
                }
            }

            stNowPtr = stNextPtr;
            stNextPtr = this->m_pstHash->GetNextPtr(stNowPtr);
        }

        return 0;
    }

    //释放
    virtual int SwapOut(HASH_PTR& stPtr)
    {
        if (!this->m_pstHash)
        {
            return -1;
        }

        if (!stPtr.IsValid())
        {
            return -2;
        }

        CT_TRACE(("swap out map cell, index = %d", stPtr.GetIndex()));
        if (!this->m_pstHash->IsNormal(stPtr.GetIndex()))
        {
            CT_ERROR(("swap out not normal cell, index = %d", stPtr.GetIndex()));
            return -3;
        }

        return this->m_pstHash->HashFreeByPtr(stPtr);
    }

    //检查更新
    virtual int CheckUpdate(int iUpdateInterval)
    {
        static int iLastUpdateTime;
        int iNow = time(NULL);
        if (iNow - iLastUpdateTime < iUpdateInterval)
        {
            return 0;
        }
        iLastUpdateTime = iNow;

        int iRet = 0;
        int iUpdateCount = 0;
        HASH_PTR stNowPtr, stNextPtr;
        stNowPtr = this->m_pstHash->GetUpdateHeadPtr();
        stNextPtr = this->m_pstHash->GetUpdateNextPtr(stNowPtr);
        for (; stNowPtr.IsValid() && iUpdateCount < MAX_HASH_UPDATE_COUNT;)
        {
            if (this->m_pstHash->IsUpdate(stNowPtr.GetIndex()) || this->m_pstHash->IsSwaping(stNowPtr.GetIndex()))
            {
                CT_TRACE(("update to db ,index = %d", stNowPtr.GetIndex()));
                iRet = (*this->m_pUpdateFunc)(stNowPtr);
                if (iRet == 0)
                {
                    this->m_pstHash->SetSwaping(stNowPtr);
                    iUpdateCount++;
                }
            }

            stNowPtr = stNextPtr;
            stNextPtr = this->m_pstHash->GetUpdateNextPtr(stNowPtr);
        }

        CT_TRACE(("update %d cell to db", iUpdateCount));
        return 0;
    }

protected:
};

#endif

